/************************************************************************

								Heroes IV
					  Copyright 2001, The 3DO Company

	------------------------------------------------------------------
  						       caravan_set.cpp

	$Header: $

	$NoKeywords: $

 ************************************************************************/
// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "caravan_set.h"

#include <string>
#include "adventure_object.h"
#include "caravan.h"
#include "town.h"

namespace
{
	enum t_compare
	{
		k_compare_less = -1,
		k_compare_equal,
		k_compare_greater
	};

	// -------------------------------------------------------------------
	// Compare the arrival dates of the caravans
	// -------------------------------------------------------------------
	inline t_compare compare_arrivals( t_caravan_ptr const & caravan1, t_caravan_ptr const & caravan2 )
	{
		int arrival_day_1 = caravan1->get_arrival_day();
		int arrival_day_2 = caravan2->get_arrival_day();

		if ( arrival_day_1 < arrival_day_2 )
			return k_compare_less;
		else if ( arrival_day_1 > arrival_day_2 )
			return k_compare_greater;

		return k_compare_equal;
	}

	// -------------------------------------------------------------------
	// Compare destination or origin objects
	// -------------------------------------------------------------------
	inline t_compare compare_objects( t_adventure_object const * object1, t_adventure_object const * object2 )
	{
		// NULLs before anything else
		if ( object1 == NULL )
		{
			if ( object2 == NULL )
			{
				return k_compare_equal;
			}
			else
			{
				return k_compare_less;
			}
		}
		else if ( object2 == NULL )
		{
			return k_compare_greater;
		}

		std::string name1 = object1->get_name();
		std::string name2 = object2->get_name();

		if ( name1 < name2 )
			return k_compare_less;
		else if ( name1 > name2 )
			return k_compare_greater;

		if ( object1 > object2 )
			return k_compare_less;
		else if ( object1 < object2 )
			return k_compare_greater;

		return k_compare_equal;
	}

	// -------------------------------------------------------------------
	// Compare the destinations of the caravans
	// -------------------------------------------------------------------
	inline t_compare compare_destinations( t_caravan_ptr const & caravan1, t_caravan_ptr const & caravan2 )
	{
		return compare_objects( caravan1->get_destination().get(), caravan2->get_destination().get() );
	}

	// -------------------------------------------------------------------
	// Compare origin objects
	// -------------------------------------------------------------------
	inline t_compare compare_origins( t_caravan_ptr const & caravan1, t_caravan_ptr const & caravan2 )
	{
		std::string name1 = caravan1->get_origin_name();
		std::string name2 = caravan2->get_origin_name();

		if ( name1 < name2 )
			return k_compare_less;
		else if ( name1 > name2 )
			return k_compare_greater;
		else
			return k_compare_equal;
	}

	// -------------------------------------------------------------------
	// Compare the owners of the caravans
	// -------------------------------------------------------------------
	inline t_compare compare_players( t_caravan_ptr const & caravan1, t_caravan_ptr const & caravan2 )
	{
		int owner1 = caravan1->get_owner_number();
		int owner2 = caravan2->get_owner_number();

		if ( owner1 < owner2 )
			return k_compare_less;
		else if ( owner1 > owner2 )
			return k_compare_greater;
		else
			return k_compare_equal;
	}

}

// -------------------------------------------------------------------
// Caravan sorting predicate
// -------------------------------------------------------------------
bool t_caravan_sorting_predicate::operator()( t_caravan_ptr const & caravan1, t_caravan_ptr const & caravan2 ) const
{
	t_compare compare;

	compare = compare_destinations( caravan1, caravan2 );

	if ( compare == k_compare_less )
		return true;
	else if ( compare == k_compare_greater )
		return false;
		
	compare = compare_players( caravan1, caravan2 );

	if ( compare == k_compare_less )
		return true;
	else if ( compare == k_compare_greater )
		return false;

	compare = compare_arrivals( caravan1, caravan2 );

	if ( compare == k_compare_less )
		return true;
	else if ( compare == k_compare_greater )
		return false;


	if ( compare_origins( caravan1, caravan2 ) == k_compare_less )
		return true;

	return false;
}


// -------------------------------------------------------------------
// Get the lower bound of caravans that have the given town as
// their destination. 
// -------------------------------------------------------------------
t_caravan_set::iterator t_caravan_set::get_lower_bound_of_destination( t_town * destination )
{
	t_caravan_ptr key = new t_caravan( destination->get_map(), -1, NULL, destination );

	return lower_bound( key );
}

// -------------------------------------------------------------------
// Get the lower bound of caravans that have the given town as
// their destination. 
// -------------------------------------------------------------------
t_caravan_set::const_iterator t_caravan_set::get_lower_bound_of_destination( t_town * destination ) const
{
	t_caravan_ptr key = new t_caravan( destination->get_map(), -1, NULL, destination );

	return lower_bound( key );
}

